package cHelper

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"unicode"
)

var (
	base = []string{
		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", // 10
		"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", // 26,36
		"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", // 26,62
		"~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "=", "-", "{", "}", "[", "]", ":", ";", "<", ">", "?", "/", ".", ",", "|", // 28,90
	}
)

// ToFloat32 字符串转32位浮点数
func ToFloat32(s string) float32 {
	res, _ := strconv.ParseFloat(s, 32)
	return float32(res)
}

// ToFloat64 字符串转64位浮点数
func ToFloat64(s string) float64 {
	res, _ := strconv.ParseFloat(s, 64)
	return res
}

// ToBool 字符串转布尔值
func ToBool(s string) bool {
	res, _ := strconv.ParseBool(s)
	return res
}

// ToInt8 字符串转int8
func ToInt8(s string) int8 {
	res, _ := strconv.ParseInt(s, 10, 8)
	return int8(res)
}

// ToInt 字符串转int
func ToInt(s string) int {
	res, _ := strconv.Atoi(s)
	return res
}

// ToInt32 字符串转int32
func ToInt32(s string) int32 {
	res, _ := strconv.ParseInt(s, 10, 32)
	return int32(res)
}

// ToInt64 字符串转int64
func ToInt64(s string) int64 {
	res, _ := strconv.ParseInt(s, 10, 64)
	return res
}

// ToUint8 字符串转uint8
func ToUint8(s string) uint8 {
	res, _ := strconv.ParseInt(s, 10, 8)
	return uint8(res)
}

// ToUint 字符串转uint
func ToUint(s string) uint {
	res, _ := strconv.Atoi(s)
	return uint(res)
}

// ToUint32 字符串转uint32
func ToUint32(s string) uint32 {
	res, _ := strconv.ParseInt(s, 10, 32)
	return uint32(res)
}

// ToUint64 字符串转uint64
func ToUint64(s string) uint64 {
	res, _ := strconv.ParseInt(s, 10, 64)
	return uint64(res)
}

// ToString 所有类型转字符串
func ToString(data interface{}) string {
	var res string
	if data == nil {
		return res
	}

	switch data.(type) {
	case int8, int16, int32, int, int64, uint8, uint16, uint32, uint, uint64:
		res = fmt.Sprintf("%d", data)
	case float32, float64:
		res = fmt.Sprintf("%.f", data)
	default:
		res = fmt.Sprintf("%v", data)
	}
	return res
}

// Ucfirst 首字母大写
func Ucfirst(s string) string {
	if len(s) < 1 {
		return ""
	}

	data := []rune(s)
	if data[0] >= 97 && data[0] <= 122 {
		data[0] = data[0] - 32
	}

	return string(data)
}

// ReplaceAll 多个字符串同时替换为同一个
func ReplaceAll(src string, old []string, new string) string {
	if len(old) <= 0 {
		return src
	}
	for _, oldStr := range old {
		src = strings.ReplaceAll(src, oldStr, new)
	}

	return src
}

func RandomStr(length int, randomType RandomType) string {
	var res string
	var randomBase []string
	var randomBaseLen int
	switch randomType {
	default:
		fallthrough
	case RandomType_All:
		randomBase = base
	case RandomType_Number:
		randomBase = base[0:9]
	case RandomType_Char:
		randomBase = base[10:61]
	case RandomType_LowerChar:
		randomBase = base[10:35]
	case RandomType_UpperChar:
		randomBase = base[36:61]
	case RandomType_Symbol:
		randomBase = base[62:89]
	case RandomType_NumberAndChar:
		randomBase = base[0:61]
	case RandomType_CharAndSymbol:
		randomBase = base[10:89]
	}
	randomBaseLen = len(randomBase)

	if length < 1 {
		return ""
	}

	for i := 0; i < length; i++ {
		num := rand.Intn(randomBaseLen - 1)
		char := randomBase[num]
		res = res + char
	}

	return res
}

func ToSnake(data string) string {
	source := []rune(data)
	target := []rune{}

	for i, r := range source {
		if unicode.IsUpper(r) {
			if i != 0 {
				target = append(target, 95)
			}
			target = append(target, unicode.ToLower(r))
		} else {
			target = append(target, r)
		}
	}

	return string(target)
}

func ToSnakeWithChar(data string, r rune) string {
	source := []rune(data)
	target := []rune{}

	for i, r := range source {
		if unicode.IsUpper(r) {
			if i != 0 {
				target = append(target, r)
			}
			target = append(target, unicode.ToLower(r))
		} else {
			target = append(target, r)
		}
	}

	return string(target)
}

func ToCamel(data string) string {
	sources := strings.Split(data, "_")
	target := ""

	for _, source := range sources {
		target = target + strings.Title(source) //nolint:staticcheck
	}

	return target
}

func ToCamelWithChars(data string, chars []string) string {
	sources := []string{data}

	for _, char := range chars {
		sourcesItem := []string{}
		for _, source := range sources {
			temp := strings.Split(source, char)
			sourcesItem = append(sourcesItem, temp...)
		}
		sources = sourcesItem
	}

	target := ""

	for _, source := range sources {
		target = target + strings.Title(source) //nolint:staticcheck
	}

	return target
}
